iT邦幫忙

2022 iThome 鐵人賽

DAY 28
0
  • 為什麼函式庫實作如此複雜?
  • 如果函式庫(或框架)已經處理完畢,為什麼還需要暸解他裡頭的運作細節?

使用函式庫,若能暸解內部操控 DOM 的原則與細節,你可以寫出更快更好的程式,或者是在自己的程式裡運用那些技巧。

這章想學到什麼?

  • 注入 HTML 到 DOM 裡
  • insertAdjacentHTML
  • 從 HTML 轉換成 DOM
  • 插入文件
  • 執行腳本程式

程式碼閱讀練習與撰寫

insertAdjacentHTML

<div id="one">one</div>
var d1 = document.getElementById('one');
d1.insertAdjacentHTML('afterend', '<div id="two">two</div>');

// At this point, the new structure is:
// <div id="one">one</div><div id="two">two</div>

從 HTML 轉換成 DOM

//確保自我結束元素可被正常解析
var tags = /^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i;

function convert(html) {
    return html.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag) {
        return tags.test(tag) ? 
            all :
            front + "></" + tag + ">";
    })
}

console.log(convert("<a/>" === "<a></a>"))

//從某 HTML 字串產生 DOM 節點
function getNodes(htmlString, doc) {
    var map = {
        "<td":[3,"<table><tbody><tr>", "</tr></tbody></table>"],
        "<th":[3,"<table><tbody><tr>", "</tr></tbody></table>"],
        "<tr":[2,"<table><thead>", "</thead></table>"]
    }


var tagName = htmlString.match(/<\w+/),
    mapEntry = tagName ? map[tagName[0]] : null;
    if(!mapEntry) mapEntry = [0, " ", " " ];
    
var div = (doc || document).createElement("div");
div.innerHTML = mapEntry[1] + htmlString + mapEntry[2];

    while(mapEntry[0]--) div = div.lastChild;
    
    return div.childNodes;
}

getNodes("<td>test</td><td>test2</td>") //NodeList(2) [td, td]

插入文件

function getNodes(htmlString, doc, fragment) {

    var map = {
        "<td":[3,"<table><tbody><tr>", "</tr></tbody></table>"],
        "<th":[3,"<table><tbody><tr>", "</tr></tbody></table>"],
        "<tr":[2,"<table><thead>", "</thead></table>"]
    }

console.log(htmlString)

var tagName = htmlString.match(/<\w+/),
    mapEntry = tagName ? map[tagName[0]] : null;
    if(!mapEntry) mapEntry = [0, " ", " " ];
    
var div = (doc || document).createElement("div");
div.innerHTML = mapEntry[1] + htmlString + mapEntry[2];

    while(mapEntry[0]--) div = div.lastChild;
    
    if(fragment) {
	while(div.firstChild) {
  	fragment.appendChild(div.firstChild)
  }
}
    
    return div.childNodes;
}

function root(elem, cur) {
	return elem.nodeName.toLowerCase() === "table" && cur.nodeName.toLowerCase() === "tr" ? (elem.getElementsByTagName("tbody")[0] || elem.appendChild(elem.ownerDocument.createElement("tbody"))) : elem;
}


window.onload = function(){
    function insert(elems, args, callback) {
        if(elems.length) {
            var doc = elems[0].ownerDocument || elems[0],
            fragment = doc.createDocumentFragment(),
            scripts = getNodes(args[0], doc, fragment),
            first = fragment.firstChild;
            
            if(first) {
                for (var i = 0; elems[i]; i++) {
                    callback.call(root(elems[i], first), i > 0 ? fragment.cloneNode(true) : fragment);
                }
            }
        }
    }
    
    var divs = document.getElementsByTagName("div");
    
    insert(divs, ["<b>First</b>"], function (fragment) { this.appendChild(fragment) })
}

執行腳本程式

//jQuery 部分實作,無法執行
function globalEval(data) {
    data = data.replace(/^\s+|\s+$/g, "");
    
    if(data) {
        var head = document.getElementsByTagName("head")[0] || document.documentElement,
        script = document.createElement("script");
        
        script.type = "text/javascript";
        script.text = data;
        
        head.insertBefore(script, head.firstChild);
        head.removeChild(script);
    }
}

參考資料

https://developer.mozilla.org/zh-TW/docs/Web/API/Element/insertAdjacentHTML
https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment


上一篇
從事件中倖存(下) Day26
下一篇
操控 DOM(下) Day28
系列文
JS 忍者訓練計畫30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言